/** @file
  UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface
  for upper layer application to execute UFS-supported SCSI cmds.

  Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#ifndef _UFS_PASS_THRU_HCI_H_
#define _UFS_PASS_THRU_HCI_H_

//
// Host Capabilities Register Offsets
//
#define UFS_HC_CAP_OFFSET          0x0000  // Controller Capabilities
#define UFS_HC_VER_OFFSET          0x0008  // Version
#define UFS_HC_DDID_OFFSET         0x0010  // Device ID and Device Class
#define UFS_HC_PMID_OFFSET         0x0014  // Product ID and Manufacturer ID
#define UFS_HC_AHIT_OFFSET         0x0018  // Auto-Hibernate Idle Timer
//
// Operation and Runtime Register Offsets
//
#define UFS_HC_IS_OFFSET           0x0020  // Interrupt Status
#define UFS_HC_IE_OFFSET           0x0024  // Interrupt Enable
#define UFS_HC_STATUS_OFFSET       0x0030  // Host Controller Status
#define UFS_HC_ENABLE_OFFSET       0x0034  // Host Controller Enable
#define UFS_HC_UECPA_OFFSET        0x0038  // Host UIC Error Code PHY Adapter Layer
#define UFS_HC_UECDL_OFFSET        0x003c  // Host UIC Error Code Data Link Layer
#define UFS_HC_UECN_OFFSET         0x0040  // Host UIC Error Code Network Layer
#define UFS_HC_UECT_OFFSET         0x0044  // Host UIC Error Code Transport Layer
#define UFS_HC_UECDME_OFFSET       0x0048  // Host UIC Error Code DME
#define UFS_HC_UTRIACR_OFFSET      0x004c  // UTP Transfer Request Interrupt Aggregation Control Register
//
// UTP Transfer Register Offsets
//
#define UFS_HC_UTRLBA_OFFSET       0x0050  // UTP Transfer Request List Base Address
#define UFS_HC_UTRLBAU_OFFSET      0x0054  // UTP Transfer Request List Base Address Upper 32-Bits
#define UFS_HC_UTRLDBR_OFFSET      0x0058  // UTP Transfer Request List Door Bell Register
#define UFS_HC_UTRLCLR_OFFSET      0x005c  // UTP Transfer Request List CLear Register
#define UFS_HC_UTRLRSR_OFFSET      0x0060  // UTP Transfer Request Run-Stop Register
//
// UTP Task Management Register Offsets
//
#define UFS_HC_UTMRLBA_OFFSET      0x0070  // UTP Task Management Request List Base Address
#define UFS_HC_UTMRLBAU_OFFSET     0x0074  // UTP Task Management Request List Base Address Upper 32-Bits
#define UFS_HC_UTMRLDBR_OFFSET     0x0078  // UTP Task Management Request List Door Bell Register
#define UFS_HC_UTMRLCLR_OFFSET     0x007c  // UTP Task Management Request List CLear Register
#define UFS_HC_UTMRLRSR_OFFSET     0x0080  // UTP Task Management Run-Stop Register
//
// UIC Command Register Offsets
//
#define UFS_HC_UIC_CMD_OFFSET      0x0090  // UIC Command Register
#define UFS_HC_UCMD_ARG1_OFFSET    0x0094  // UIC Command Argument 1
#define UFS_HC_UCMD_ARG2_OFFSET    0x0098  // UIC Command Argument 2
#define UFS_HC_UCMD_ARG3_OFFSET    0x009c  // UIC Command Argument 3
//
// UMA Register Offsets
//
#define UFS_HC_UMA_OFFSET          0x00b0  // Reserved for Unified Memory Extension

#define UFS_HC_HCE_EN              BIT0
#define UFS_HC_HCS_DP              BIT0
#define UFS_HC_HCS_UCRDY           BIT3
#define UFS_HC_IS_ULSS             BIT8
#define UFS_HC_IS_UCCS             BIT10
#define UFS_HC_CAP_64ADDR          BIT24
#define UFS_HC_CAP_NUTMRS          (BIT16 | BIT17 | BIT18)
#define UFS_HC_CAP_NUTRS           (BIT0 | BIT1 | BIT2 | BIT3 | BIT4)
#define UFS_HC_UTMRLRSR            BIT0
#define UFS_HC_UTRLRSR             BIT0

//
// The initial value of the OCS field of UTP TRD or TMRD descriptor
// defined in JEDEC JESD223 specification
//
#define UFS_HC_TRD_OCS_INIT_VALUE  0x0F

//
// A maximum of length of 256KB is supported by PRDT entry
//
#define UFS_MAX_DATA_LEN_PER_PRD   0x40000

#define UFS_STORAGE_COMMAND_TYPE   0x01

#define UFS_REGULAR_COMMAND        0x00
#define UFS_INTERRUPT_COMMAND      0x01

#define UFS_LUN_0                  0x00
#define UFS_LUN_1                  0x01
#define UFS_LUN_2                  0x02
#define UFS_LUN_3                  0x03
#define UFS_LUN_4                  0x04
#define UFS_LUN_5                  0x05
#define UFS_LUN_6                  0x06
#define UFS_LUN_7                  0x07
#define UFS_WLUN_REPORT_LUNS       0x81
#define UFS_WLUN_UFS_DEV           0xD0
#define UFS_WLUN_BOOT              0xB0
#define UFS_WLUN_RPMB              0xC4

#pragma pack(1)

//
// UFSHCI 2.0 Spec Section 5.2.1 Offset 00h: CAP - Controller Capabilities
//
typedef struct {
  UINT8  Nutrs:4;      // Number of UTP Transfer Request Slots
  UINT8  Rsvd1:4;

  UINT8  NoRtt;        // Number of outstanding READY TO TRANSFER (RTT) requests supported

  UINT8  Nutmrs:3;     // Number of UTP Task Management Request Slots
  UINT8  Rsvd2:4;
  UINT8  AutoHs:1;     // Auto-Hibernation Support

  UINT8  As64:1;       // 64-bit addressing supported
  UINT8  Oodds:1;      // Out of order data delivery supported
  UINT8  UicDmetms:1;  // UIC DME_TEST_MODE command supported
  UINT8  Ume:1;        // Reserved for Unified Memory Extension
  UINT8  Rsvd4:4;
} UFS_HC_CAP;

//
// UFSHCI 2.0 Spec Section 5.2.2 Offset 08h: VER - UFS Version
//
typedef struct {
  UINT8  Vs:4;         // Version Suffix
  UINT8  Mnr:4;        // Minor version number

  UINT8  Mjr;          // Major version number

  UINT16 Rsvd1;
} UFS_HC_VER;

//
// UFSHCI 2.0 Spec Section 5.2.3 Offset 10h: HCPID - Host Controller Product ID
//
#define UFS_HC_PID     UINT32

//
// UFSHCI 2.0 Spec Section 5.2.4 Offset 14h: HCMID - Host Controller Manufacturer ID
//
#define UFS_HC_MID     UINT32

//
// UFSHCI 2.0 Spec Section 5.2.5 Offset 18h: AHIT - Auto-Hibernate Idle Timer
//
typedef struct {
  UINT32 Ahitv:10;     // Auto-Hibernate Idle Timer Value
  UINT32 Ts:3;         // Timer scale
  UINT32 Rsvd1:19;
} UFS_HC_AHIT;

//
// UFSHCI 2.0 Spec Section 5.3.1 Offset 20h: IS - Interrupt Status
//
typedef struct {
  UINT16 Utrcs:1;      // UTP Transfer Request Completion Status
  UINT16 Udepri:1;     // UIC DME_ENDPOINT_RESET Indication
  UINT16 Ue:1;         // UIC Error
  UINT16 Utms:1;       // UIC Test Mode Status

  UINT16 Upms:1;       // UIC Power Mode Status
  UINT16 Uhxs:1;       // UIC Hibernate Exit Status
  UINT16 Uhes:1;       // UIC Hibernate Enter Status
  UINT16 Ulls:1;       // UIC Link Lost Status

  UINT16 Ulss:1;       // UIC Link Startup Status
  UINT16 Utmrcs:1;     // UTP Task  Management Request Completion Status
  UINT16 Uccs:1;       // UIC Command Completion Status
  UINT16 Dfes:1;       // Device Fatal Error Status

  UINT16 Utpes:1;      // UTP Error Status
  UINT16 Rsvd1:3;

  UINT16 Hcfes:1;      // Host Controller Fatal Error Status
  UINT16 Sbfes:1;      // System Bus Fatal Error Status
  UINT16 Rsvd2:14;
} UFS_HC_IS;

//
// UFSHCI 2.0 Spec Section 5.3.2 Offset 24h: IE - Interrupt Enable
//
typedef struct {
  UINT16 Utrce:1;      // UTP Transfer Request Completion Enable
  UINT16 Udeprie:1;    // UIC DME_ENDPOINT_RESET Enable
  UINT16 Uee:1;        // UIC Error Enable
  UINT16 Utmse:1;      // UIC Test Mode Status Enable

  UINT16 Upmse:1;      // UIC Power Mode Status Enable
  UINT16 Uhxse:1;      // UIC Hibernate Exit Status Enable
  UINT16 Uhese:1;      // UIC Hibernate Enter Status Enable
  UINT16 Ullse:1;      // UIC Link Lost Status Enable

  UINT16 Ulsse:1;      // UIC Link Startup Status Enable
  UINT16 Utmrce:1;     // UTP Task  Management Request Completion Enable
  UINT16 Ucce:1;       // UIC Command Completion Enable
  UINT16 Dfee:1;       // Device Fatal Error Enable

  UINT16 Utpee:1;      // UTP Error Enable
  UINT16 Rsvd1:3;

  UINT16 Hcfee:1;      // Host Controller Fatal Error Enable
  UINT16 Sbfee:1;      // System Bus Fatal Error Enable
  UINT16 Rsvd2:14;
} UFS_HC_IE;

//
// UFSHCI 2.0 Spec Section 5.3.3 Offset 30h: HCS - Host Controller Status
//
typedef struct {
  UINT8  Dp:1;         // Device Present
  UINT8  UtrlRdy:1;    // UTP Transfer Request List Ready
  UINT8  UtmrlRdy:1;   // UTP Task Management Request List Ready
  UINT8  UcRdy:1;      // UIC COMMAND Ready
  UINT8  Rsvd1:4;

  UINT8  Upmcrs:3;     // UIC Power Mode Change Request Status
  UINT8  Rsvd2:1;      // UIC Hibernate Exit Status Enable
  UINT8  Utpec:4;      // UTP Error Code

  UINT8  TtagUtpE;     // Task Tag of UTP error
  UINT8  TlunUtpE;     // Target LUN of UTP error
} UFS_HC_STATUS;

//
// UFSHCI 2.0 Spec Section 5.3.4 Offset 34h: HCE - Host Controller Enable
//
typedef struct {
  UINT32 Hce:1;        // Host Controller Enable
  UINT32 Rsvd1:31;
} UFS_HC_ENABLE;

//
// UFSHCI 2.0 Spec Section 5.3.5 Offset 38h: UECPA - Host UIC Error Code PHY Adapter Layer
//
typedef struct {
  UINT32 Ec:5;         // UIC PHY Adapter Layer Error Code
  UINT32 Rsvd1:26;
  UINT32 Err:1;        // UIC PHY Adapter Layer Error
} UFS_HC_UECPA;

//
// UFSHCI 2.0 Spec Section 5.3.6 Offset 3ch: UECDL - Host UIC Error Code Data Link Layer
//
typedef struct {
  UINT32 Ec:15;        // UIC Data Link Layer Error Code
  UINT32 Rsvd1:16;
  UINT32 Err:1;        // UIC Data Link Layer Error
} UFS_HC_UECDL;

//
// UFSHCI 2.0 Spec Section 5.3.7 Offset 40h: UECN - Host UIC Error Code Network Layer
//
typedef struct {
  UINT32 Ec:3;         // UIC Network Layer Error Code
  UINT32 Rsvd1:28;
  UINT32 Err:1;        // UIC Network Layer Error
} UFS_HC_UECN;

//
// UFSHCI 2.0 Spec Section 5.3.8 Offset 44h: UECT - Host UIC Error Code Transport Layer
//
typedef struct {
  UINT32 Ec:7;         // UIC Transport Layer Error Code
  UINT32 Rsvd1:24;
  UINT32 Err:1;        // UIC Transport Layer Error
} UFS_HC_UECT;

//
// UFSHCI 2.0 Spec Section 5.3.9 Offset 48h: UECDME - Host UIC Error Code
//
typedef struct {
  UINT32 Ec:1;         // UIC DME Error Code
  UINT32 Rsvd1:30;
  UINT32 Err:1;        // UIC DME Error
} UFS_HC_UECDME;

//
// UFSHCI 2.0 Spec Section 5.3.10 Offset 4Ch: UTRIACR - UTP Transfer Request Interrupt Aggregation Control Register
//
typedef struct {
  UINT8  IaToVal;      // Interrupt aggregation timeout value

  UINT8  IacTh:5;      // Interrupt aggregation counter threshold
  UINT8  Rsvd1:3;

  UINT8  Ctr:1;        // Counter and Timer Reset
  UINT8  Rsvd2:3;
  UINT8  Iasb:1;       // Interrupt aggregation status bit
  UINT8  Rsvd3:3;

  UINT8  IapwEn:1;     // Interrupt aggregation parameter write enable
  UINT8  Rsvd4:6;
  UINT8  IaEn:1;       // Interrupt Aggregation Enable/Disable
} UFS_HC_UTRIACR;

//
// UFSHCI 2.0 Spec Section 5.4.1 Offset 50h: UTRLBA - UTP Transfer Request List Base Address
//
typedef struct {
  UINT32 Rsvd1:10;
  UINT32 UtrlBa:22;    // UTP Transfer Request List Base Address
} UFS_HC_UTRLBA;

//
// UFSHCI 2.0 Spec Section 5.4.2 Offset 54h: UTRLBAU - UTP Transfer Request List Base Address Upper 32-bits
//
#define UFS_HC_UTRLBAU UINT32

//
// UFSHCI 2.0 Spec Section 5.4.3 Offset 58h: UTRLDBR - UTP Transfer Request List Door Bell Register
//
#define UFS_HC_UTRLDBR UINT32

//
// UFSHCI 2.0 Spec Section 5.4.4 Offset 5Ch: UTRLCLR - UTP Transfer Request List CLear Register
//
#define UFS_HC_UTRLCLR UINT32

#if 0
//
// UFSHCI 2.0 Spec Section 5.4.5 Offset 60h: UTRLRSR - UTP Transfer Request List Run Stop Register
//
typedef struct {
  UINT32 UtrlRsr:1;    // UTP Transfer Request List Run-Stop Register
  UINT32 Rsvd1:31;
} UFS_HC_UTRLRSR;
#endif

//
// UFSHCI 2.0 Spec Section 5.5.1 Offset 70h: UTMRLBA - UTP Task Management Request List Base Address
//
typedef struct {
  UINT32 Rsvd1:10;
  UINT32 UtmrlBa:22;   // UTP Task Management Request List Base Address
} UFS_HC_UTMRLBA;

//
// UFSHCI 2.0 Spec Section 5.5.2 Offset 74h: UTMRLBAU - UTP Task Management Request List Base Address Upper 32-bits
//
#define UFS_HC_UTMRLBAU UINT32

//
// UFSHCI 2.0 Spec Section 5.5.3 Offset 78h: UTMRLDBR - UTP Task Management Request List Door Bell Register
//
typedef struct {
  UINT32 UtmrlDbr:8;   // UTP Task Management Request List Door bell Register
  UINT32 Rsvd1:24;
} UFS_HC_UTMRLDBR;

//
// UFSHCI 2.0 Spec Section 5.5.4 Offset 7Ch: UTMRLCLR - UTP Task Management Request List CLear Register
//
typedef struct {
  UINT32 UtmrlClr:8;   // UTP Task Management List Clear Register
  UINT32 Rsvd1:24;
} UFS_HC_UTMRLCLR;

#if 0
//
// UFSHCI 2.0 Spec Section 5.5.5 Offset 80h: UTMRLRSR - UTP Task Management Request List Run Stop Register
//
typedef struct {
  UINT32 UtmrlRsr:1;   // UTP Task Management Request List Run-Stop Register
  UINT32 Rsvd1:31;
} UFS_HC_UTMRLRSR;
#endif

//
// UFSHCI 2.0 Spec Section 5.6.1 Offset 90h: UICCMD - UIC Command
//
typedef struct {
  UINT32 CmdOp:8;      // Command Opcode
  UINT32 Rsvd1:24;
} UFS_HC_UICCMD;

//
// UFSHCI 2.0 Spec Section 5.6.2 Offset 94h: UICCMDARG1 - UIC Command Argument 1
//
#define UFS_HC_UICCMD_ARG1 UINT32

//
// UFSHCI 2.0 Spec Section 5.6.2 Offset 98h: UICCMDARG2 - UIC Command Argument 2
//
#define UFS_HC_UICCMD_ARG2 UINT32

//
// UFSHCI 2.0 Spec Section 5.6.2 Offset 9ch: UICCMDARG3 - UIC Command Argument 3
//
#define UFS_HC_UICCMD_ARG3 UINT32

//
// UIC command opcodes
//
typedef enum {
  UfsUicDmeGet            = 0x01,
  UfsUicDmeSet            = 0x02,
  UfsUicDmePeerGet        = 0x03,
  UfsUicDmePeerSet        = 0x04,
  UfsUicDmePwrOn          = 0x10,
  UfsUicDmePwrOff         = 0x11,
  UfsUicDmeEnable         = 0x12,
  UfsUicDmeReset          = 0x14,
  UfsUicDmeEndpointReset  = 0x15,
  UfsUicDmeLinkStartup    = 0x16,
  UfsUicDmeHibernateEnter = 0x17,
  UfsUicDmeHibernateExit  = 0x18,
  UfsUicDmeTestMode       = 0x1A
} UFS_UIC_OPCODE;

//
// UTP Transfer Request Descriptor
//
typedef struct {
  //
  // DW0
  //
  UINT32 Rsvd1:24;
  UINT32 Int:1;               /* Interrupt */
  UINT32 Dd:2;                /* Data Direction */
  UINT32 Rsvd2:1;
  UINT32 Ct:4;                /* Command Type */

  //
  // DW1
  //
  UINT32 Rsvd3;

  //
  // DW2
  //
  UINT32 Ocs:8;               /* Overall Command Status */
  UINT32 Rsvd4:24;

  //
  // DW3
  //
  UINT32 Rsvd5;

  //
  // DW4
  //
  UINT32 Rsvd6:7;
  UINT32 UcdBa:25;            /* UTP Command Descriptor Base Address */

  //
  // DW5
  //
  UINT32 UcdBaU;              /* UTP Command Descriptor Base Address Upper 32-bits */

  //
  // DW6
  //
  UINT16 RuL;                 /* Response UPIU Length */
  UINT16 RuO;                 /* Response UPIU Offset */

  //
  // DW7
  //
  UINT16 PrdtL;               /* PRDT Length */
  UINT16 PrdtO;               /* PRDT Offset */
} UTP_TRD;

typedef struct {
  //
  // DW0
  //
  UINT32 Rsvd1:2;
  UINT32 DbAddr:30;           /* Data Base Address */

  //
  // DW1
  //
  UINT32 DbAddrU;             /* Data Base Address Upper 32-bits */

  //
  // DW2
  //
  UINT32 Rsvd2;

  //
  // DW3
  //
  UINT32 DbCount:18;          /* Data Byte Count */
  UINT32 Rsvd3:14;
} UTP_TR_PRD;

//
// UFS 2.0 Spec Section 10.5.3 - UTP Command UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8  TransCode:6;         /* Transaction Type - 0x01*/
  UINT8  Dd:1;
  UINT8  Hd:1;
  UINT8  Flags;
  UINT8  Lun;
  UINT8  TaskTag;             /* Task Tag */

  //
  // DW1
  //
  UINT8  CmdSet:4;            /* Command Set Type */
  UINT8  Rsvd1:4;
  UINT8  Rsvd2;
  UINT8  Rsvd3;
  UINT8  Rsvd4;

  //
  // DW2
  //
  UINT8  EhsLen;              /* Total EHS Length - 0x00 */
  UINT8  Rsvd5;
  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */

  //
  // DW3
  //
  UINT32 ExpDataTranLen;      /* Expected Data Transfer Length - Big Endian */

  //
  // DW4 - DW7
  //
  UINT8  Cdb[16];
} UTP_COMMAND_UPIU;

//
// UFS 2.0 Spec Section 10.5.4 - UTP Response UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8  TransCode:6;         /* Transaction Type - 0x21*/
  UINT8  Dd:1;
  UINT8  Hd:1;
  UINT8  Flags;
  UINT8  Lun;
  UINT8  TaskTag;             /* Task Tag */

  //
  // DW1
  //
  UINT8  CmdSet:4;            /* Command Set Type */
  UINT8  Rsvd1:4;
  UINT8  Rsvd2;
  UINT8  Response;            /* Response */
  UINT8  Status;              /* Status */

  //
  // DW2
  //
  UINT8  EhsLen;              /* Total EHS Length - 0x00 */
  UINT8  DevInfo;             /* Device Information */
  UINT16 DataSegLen;          /* Data Segment Length - Big Endian */

  //
  // DW3
  //
  UINT32 ResTranCount;        /* Residual Transfer Count - Big Endian */

  //
  // DW4 - DW7
  //
  UINT8  Rsvd3[16];

  //
  // Data Segment - Sense Data
  //
  UINT16 SenseDataLen;        /* Sense Data Length - Big Endian */
  UINT8  SenseData[18];       /* Sense Data */
} UTP_RESPONSE_UPIU;

//
// UFS 2.0 Spec Section 10.5.5 - UTP Data-Out UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8  TransCode:6;         /* Transaction Type - 0x02*/
  UINT8  Dd:1;
  UINT8  Hd:1;
  UINT8  Flags;
  UINT8  Lun;
  UINT8  TaskTag;             /* Task Tag */

  //
  // DW1
  //
  UINT8  Rsvd1[4];

  //
  // DW2
  //
  UINT8  EhsLen;              /* Total EHS Length - 0x00 */
  UINT8  Rsvd2;
  UINT16 DataSegLen;          /* Data Segment Length - Big Endian */

  //
  // DW3
  //
  UINT32 DataBufOffset;       /* Data Buffer Offset - Big Endian */

  //
  // DW4
  //
  UINT32 DataTranCount;       /* Data Transfer Count - Big Endian */

  //
  // DW5 - DW7
  //
  UINT8  Rsvd3[12];

  //
  // Data Segment - Data to be sent out
  //
  //UINT8  Data[];            /* Data to be sent out, maximum is 65535 bytes */
} UTP_DATA_OUT_UPIU;

//
// UFS 2.0 Spec Section 10.5.6 - UTP Data-In UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8  TransCode:6;         /* Transaction Type - 0x22*/
  UINT8  Dd:1;
  UINT8  Hd:1;
  UINT8  Flags;
  UINT8  Lun;
  UINT8  TaskTag;             /* Task Tag */

  //
  // DW1
  //
  UINT8  Rsvd1[4];

  //
  // DW2
  //
  UINT8  EhsLen;              /* Total EHS Length - 0x00 */
  UINT8  Rsvd2;
  UINT16 DataSegLen;          /* Data Segment Length - Big Endian */

  //
  // DW3
  //
  UINT32 DataBufOffset;       /* Data Buffer Offset - Big Endian */

  //
  // DW4
  //
  UINT32 DataTranCount;       /* Data Transfer Count - Big Endian */

  //
  // DW5 - DW7
  //
  UINT8  Rsvd3[12];

  //
  // Data Segment - Data to be read
  //
  //UINT8  Data[];            /* Data to be read, maximum is 65535 bytes */
} UTP_DATA_IN_UPIU;

//
// UFS 2.0 Spec Section 10.5.7 - UTP Ready-To-Transfer UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8  TransCode:6;         /* Transaction Type - 0x31*/
  UINT8  Dd:1;
  UINT8  Hd:1;
  UINT8  Flags;
  UINT8  Lun;
  UINT8  TaskTag;             /* Task Tag */

  //
  // DW1
  //
  UINT8  Rsvd1[4];

  //
  // DW2
  //
  UINT8  EhsLen;              /* Total EHS Length - 0x00 */
  UINT8  Rsvd2;
  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */

  //
  // DW3
  //
  UINT32 DataBufOffset;       /* Data Buffer Offset - Big Endian */

  //
  // DW4
  //
  UINT32 DataTranCount;       /* Data Transfer Count - Big Endian */

  //
  // DW5 - DW7
  //
  UINT8  Rsvd3[12];

  //
  // Data Segment - Data to be read
  //
  //UINT8  Data[];            /* Data to be read, maximum is 65535 bytes */
} UTP_RDY_TO_TRAN_UPIU;

//
// UFS 2.0 Spec Section 10.5.8 - UTP Task Management Request UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8  TransCode:6;         /* Transaction Type - 0x04*/
  UINT8  Dd:1;
  UINT8  Hd:1;
  UINT8  Flags;
  UINT8  Lun;
  UINT8  TaskTag;             /* Task Tag */

  //
  // DW1
  //
  UINT8  Rsvd1;
  UINT8  TskManFunc;          /* Task Management Function */
  UINT8  Rsvd2[2];

  //
  // DW2
  //
  UINT8  EhsLen;              /* Total EHS Length - 0x00 */
  UINT8  Rsvd3;
  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */

  //
  // DW3
  //
  UINT32 InputParam1;         /* Input Parameter 1 - Big Endian */

  //
  // DW4
  //
  UINT32 InputParam2;         /* Input Parameter 2 - Big Endian */

  //
  // DW5
  //
  UINT32 InputParam3;         /* Input Parameter 3 - Big Endian */

  //
  // DW6 - DW7
  //
  UINT8  Rsvd4[8];
} UTP_TM_REQ_UPIU;

//
// UFS 2.0 Spec Section 10.5.9 - UTP Task Management Response UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8  TransCode:6;         /* Transaction Type - 0x24*/
  UINT8  Dd:1;
  UINT8  Hd:1;
  UINT8  Flags;
  UINT8  Lun;
  UINT8  TaskTag;             /* Task Tag */

  //
  // DW1
  //
  UINT8  Rsvd1[2];
  UINT8  Resp;                /* Response */
  UINT8  Rsvd2;

  //
  // DW2
  //
  UINT8  EhsLen;              /* Total EHS Length - 0x00 */
  UINT8  Rsvd3;
  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */

  //
  // DW3
  //
  UINT32 OutputParam1;        /* Output Parameter 1 - Big Endian */

  //
  // DW4
  //
  UINT32 OutputParam2;        /* Output Parameter 2 - Big Endian */

  //
  // DW5 - DW7
  //
  UINT8  Rsvd4[12];
} UTP_TM_RESP_UPIU;

//
// UTP Task Management Request Descriptor
//
typedef struct {
  //
  // DW0
  //
  UINT32 Rsvd1:24;
  UINT32 Int:1;               /* Interrupt */
  UINT32 Rsvd2:7;

  //
  // DW1
  //
  UINT32 Rsvd3;

  //
  // DW2
  //
  UINT32 Ocs:8;               /* Overall Command Status */
  UINT32 Rsvd4:24;

  //
  // DW3
  //
  UINT32 Rsvd5;

  //
  // DW4 - DW11
  //
  UTP_TM_REQ_UPIU TmReq;      /* Task Management Request UPIU */

  //
  // DW12 - DW19
  //
  UTP_TM_RESP_UPIU TmResp;    /* Task Management Response UPIU */
} UTP_TMRD;


typedef struct {
  UINT8  Opcode;
  UINT8  DescId;
  UINT8  Index;
  UINT8  Selector;
  UINT16 Rsvd1;
  UINT16 Length;
  UINT32 Value;
  UINT32 Rsvd2;
} UTP_UPIU_TSF;

//
// UFS 2.0 Spec Section 10.5.10 - UTP Query Request UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8        TransCode:6;   /* Transaction Type - 0x16*/
  UINT8        Dd:1;
  UINT8        Hd:1;
  UINT8        Flags;
  UINT8        Rsvd1;
  UINT8        TaskTag;       /* Task Tag */

  //
  // DW1
  //
  UINT8        Rsvd2;
  UINT8        QueryFunc;     /* Query Function */
  UINT8        Rsvd3[2];

  //
  // DW2
  //
  UINT8        EhsLen;        /* Total EHS Length - 0x00 */
  UINT8        Rsvd4;
  UINT16       DataSegLen;    /* Data Segment Length - Big Endian */

  //
  // DW3 - 6
  //
  UTP_UPIU_TSF Tsf;           /* Transaction Specific Fields */

  //
  // DW7
  //
  UINT8        Rsvd5[4];

  //
  // Data Segment - Data to be transferred
  //
  //UINT8  Data[];            /* Data to be transferred, maximum is 65535 bytes */
} UTP_QUERY_REQ_UPIU;

#define QUERY_FUNC_STD_READ_REQ     0x01
#define QUERY_FUNC_STD_WRITE_REQ    0x81

typedef enum {
  UtpQueryFuncOpcodeNop      = 0x00,
  UtpQueryFuncOpcodeRdDesc   = 0x01,
  UtpQueryFuncOpcodeWrDesc   = 0x02,
  UtpQueryFuncOpcodeRdAttr   = 0x03,
  UtpQueryFuncOpcodeWrAttr   = 0x04,
  UtpQueryFuncOpcodeRdFlag   = 0x05,
  UtpQueryFuncOpcodeSetFlag  = 0x06,
  UtpQueryFuncOpcodeClrFlag  = 0x07,
  UtpQueryFuncOpcodeTogFlag  = 0x08
} UTP_QUERY_FUNC_OPCODE;

//
// UFS 2.0 Spec Section 10.5.11 - UTP Query Response UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8        TransCode:6;   /* Transaction Type - 0x36*/
  UINT8        Dd:1;
  UINT8        Hd:1;
  UINT8        Flags;
  UINT8        Rsvd1;
  UINT8        TaskTag;       /* Task Tag */

  //
  // DW1
  //
  UINT8        Rsvd2;
  UINT8        QueryFunc;     /* Query Function */
  UINT8        QueryResp;     /* Query Response */
  UINT8        Rsvd3;

  //
  // DW2
  //
  UINT8        EhsLen;        /* Total EHS Length - 0x00 */
  UINT8        DevInfo;       /* Device Information */
  UINT16       DataSegLen;    /* Data Segment Length - Big Endian */

  //
  // DW3 - 6
  //
  UTP_UPIU_TSF Tsf;           /* Transaction Specific Fields */

  //
  // DW7
  //
  UINT8        Rsvd4[4];

  //
  // Data Segment - Data to be transferred
  //
  //UINT8      Data[];        /* Data to be transferred, maximum is 65535 bytes */
} UTP_QUERY_RESP_UPIU;

typedef enum {
  UfsUtpQueryResponseSuccess             = 0x00,
  UfsUtpQueryResponseParamNotReadable    = 0xF6,
  UfsUtpQueryResponseParamNotWriteable   = 0xF7,
  UfsUtpQueryResponseParamAlreadyWritten = 0xF8,
  UfsUtpQueryResponseInvalidLen          = 0xF9,
  UfsUtpQueryResponseInvalidVal          = 0xFA,
  UfsUtpQueryResponseInvalidSelector     = 0xFB,
  UfsUtpQueryResponseInvalidIndex        = 0xFC,
  UfsUtpQueryResponseInvalidIdn          = 0xFD,
  UfsUtpQueryResponseInvalidOpc          = 0xFE,
  UfsUtpQueryResponseGeneralFailure      = 0xFF
} UTP_QUERY_RESP_CODE;

//
// UFS 2.0 Spec Section 10.5.12 - UTP Reject UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8  TransCode:6;         /* Transaction Type - 0x3F*/
  UINT8  Dd:1;
  UINT8  Hd:1;
  UINT8  Flags;
  UINT8  Lun;
  UINT8  TaskTag;             /* Task Tag */

  //
  // DW1
  //
  UINT8  Rsvd1[2];
  UINT8  Response;            /* Response - 0x01 */
  UINT8  Rsvd2;

  //
  // DW2
  //
  UINT8  EhsLen;              /* Total EHS Length - 0x00 */
  UINT8  DevInfo;             /* Device Information - 0x00 */
  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */

  //
  // DW3
  //
  UINT8  HdrSts;              /* Basic Header Status */
  UINT8  Rsvd3;
  UINT8  E2ESts;              /* End-to-End Status */
  UINT8  Rsvd4;

  //
  // DW4 - DW7
  //
  UINT8  Rsvd5[16];
} UTP_REJ_UPIU;

//
// UFS 2.0 Spec Section 10.5.13 - UTP NOP OUT UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8  TransCode:6;         /* Transaction Type - 0x00*/
  UINT8  Dd:1;
  UINT8  Hd:1;
  UINT8  Flags;
  UINT8  Rsvd1;
  UINT8  TaskTag;             /* Task Tag */

  //
  // DW1
  //
  UINT8  Rsvd2[4];

  //
  // DW2
  //
  UINT8  EhsLen;              /* Total EHS Length - 0x00 */
  UINT8  Rsvd3;
  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */

  //
  // DW3 - DW7
  //
  UINT8  Rsvd4[20];
} UTP_NOP_OUT_UPIU;

//
// UFS 2.0 Spec Section 10.5.14 - UTP NOP IN UPIU
//
typedef struct {
  //
  // DW0
  //
  UINT8  TransCode:6;         /* Transaction Type - 0x20*/
  UINT8  Dd:1;
  UINT8  Hd:1;
  UINT8  Flags;
  UINT8  Rsvd1;
  UINT8  TaskTag;             /* Task Tag */

  //
  // DW1
  //
  UINT8  Rsvd2[2];
  UINT8  Resp;                /* Response - 0x00 */
  UINT8  Rsvd3;

  //
  // DW2
  //
  UINT8  EhsLen;              /* Total EHS Length - 0x00 */
  UINT8  DevInfo;             /* Device Information - 0x00 */
  UINT16 DataSegLen;          /* Data Segment Length - Big Endian - 0x0000 */

  //
  // DW3 - DW7
  //
  UINT8  Rsvd4[20];
} UTP_NOP_IN_UPIU;

//
// UFS Descriptors
//
typedef enum {
  UfsDeviceDesc     = 0x00,
  UfsConfigDesc     = 0x01,
  UfsUnitDesc       = 0x02,
  UfsInterConnDesc  = 0x04,
  UfsStringDesc     = 0x05,
  UfsGeometryDesc   = 0x07,
  UfsPowerDesc      = 0x08
} UFS_DESC_IDN;

//
// UFS 2.0 Spec Section 14.1.6.2 - Device Descriptor
//
typedef struct {
  UINT8  Length;
  UINT8  DescType;
  UINT8  Device;
  UINT8  DevClass;
  UINT8  DevSubClass;
  UINT8  Protocol;
  UINT8  NumLun;
  UINT8  NumWLun;
  UINT8  BootEn;
  UINT8  DescAccessEn;
  UINT8  InitPowerMode;
  UINT8  HighPriorityLun;
  UINT8  SecureRemovalType;
  UINT8  SecurityLun;
  UINT8  BgOpsTermLat;
  UINT8  InitActiveIccLevel;
  UINT16 SpecVersion;
  UINT16 ManufactureDate;
  UINT8  ManufacturerName;
  UINT8  ProductName;
  UINT8  SerialName;
  UINT8  OemId;
  UINT16 ManufacturerId;
  UINT8  Ud0BaseOffset;
  UINT8  Ud0ConfParamLen;
  UINT8  DevRttCap;
  UINT16 PeriodicRtcUpdate;
  UINT8  Rsvd1[17];
  UINT8  Rsvd2[16];
} UFS_DEV_DESC;

typedef struct {
  UINT8  Length;
  UINT8  DescType;
  UINT8  Rsvd1;
  UINT8  BootEn;
  UINT8  DescAccessEn;
  UINT8  InitPowerMode;
  UINT8  HighPriorityLun;
  UINT8  SecureRemovalType;
  UINT8  InitActiveIccLevel;
  UINT16 PeriodicRtcUpdate;
  UINT8  Rsvd2[5];
} UFS_CONFIG_DESC_GEN_HEADER;

typedef struct {
  UINT8  LunEn;
  UINT8  BootLunId;
  UINT8  LunWriteProt;
  UINT8  MemType;
  UINT32 NumAllocUnits;
  UINT8  DataReliability;
  UINT8  LogicBlkSize;
  UINT8  ProvisionType;
  UINT16 CtxCap;
  UINT8  Rsvd1[3];
} UFS_UNIT_DESC_CONFIG_PARAMS;

//
// UFS 2.0 Spec Section 14.1.6.3 - Configuration Descriptor
//
typedef struct {
  UFS_CONFIG_DESC_GEN_HEADER  Header;
  UFS_UNIT_DESC_CONFIG_PARAMS UnitDescConfParams[8];
} UFS_CONFIG_DESC;

//
// UFS 2.0 Spec Section 14.1.6.4 - Geometry Descriptor
//
typedef struct {
  UINT8  Length;
  UINT8  DescType;
  UINT8  MediaTech;
  UINT8  Rsvd1;
  UINT64 TotalRawDevCapacity;
  UINT8  Rsvd2;
  UINT32 SegSize;
  UINT8  AllocUnitSize;
  UINT8  MinAddrBlkSize;
  UINT8  OptReadBlkSize;
  UINT8  OptWriteBlkSize;
  UINT8  MaxInBufSize;
  UINT8  MaxOutBufSize;
  UINT8  RpmbRwSize;
  UINT8  Rsvd3;
  UINT8  DataOrder;
  UINT8  MaxCtxIdNum;
  UINT8  SysDataTagUnitSize;
  UINT8  SysDataResUnitSize;
  UINT8  SupSecRemovalTypes;
  UINT16 SupMemTypes;
  UINT32 SysCodeMaxNumAllocUnits;
  UINT16 SupCodeCapAdjFac;
  UINT32 NonPersMaxNumAllocUnits;
  UINT16 NonPersCapAdjFac;
  UINT32 Enhance1MaxNumAllocUnits;
  UINT16 Enhance1CapAdjFac;
  UINT32 Enhance2MaxNumAllocUnits;
  UINT16 Enhance2CapAdjFac;
  UINT32 Enhance3MaxNumAllocUnits;
  UINT16 Enhance3CapAdjFac;
  UINT32 Enhance4MaxNumAllocUnits;
  UINT16 Enhance4CapAdjFac;
} UFS_GEOMETRY_DESC;

//
// UFS 2.0 Spec Section 14.1.6.5 - Unit Descriptor
//
typedef struct {
  UINT8  Length;
  UINT8  DescType;
  UINT8  UnitIdx;
  UINT8  LunEn;
  UINT8  BootLunId;
  UINT8  LunWriteProt;
  UINT8  LunQueueDep;
  UINT8  Rsvd1;
  UINT8  MemType;
  UINT8  DataReliability;
  UINT8  LogicBlkSize;
  UINT64 LogicBlkCount;
  UINT32 EraseBlkSize;
  UINT8  ProvisionType;
  UINT64 PhyMemResCount;
  UINT16 CtxCap;
  UINT8  LargeUnitGranularity;
} UFS_UNIT_DESC;

//
// UFS 2.0 Spec Section 14.1.6.6 - RPMB Unit Descriptor
//
typedef struct {
  UINT8  Length;
  UINT8  DescType;
  UINT8  UnitIdx;
  UINT8  LunEn;
  UINT8  BootLunId;
  UINT8  LunWriteProt;
  UINT8  LunQueueDep;
  UINT8  Rsvd1;
  UINT8  MemType;
  UINT8  Rsvd2;
  UINT8  LogicBlkSize;
  UINT64 LogicBlkCount;
  UINT32 EraseBlkSize;
  UINT8  ProvisionType;
  UINT64 PhyMemResCount;
  UINT8  Rsvd3[3];
} UFS_RPMB_UNIT_DESC;

typedef struct {
  UINT16 Value:10;
  UINT16 Rsvd1:4;
  UINT16 Unit:2;
} UFS_POWER_PARAM_ELEMENT;

//
// UFS 2.0 Spec Section 14.1.6.7 - Power Parameter Descriptor
//
typedef struct {
  UINT8                    Length;
  UINT8                    DescType;
  UFS_POWER_PARAM_ELEMENT  ActiveIccLevelVcc[16];
  UFS_POWER_PARAM_ELEMENT  ActiveIccLevelVccQ[16];
  UFS_POWER_PARAM_ELEMENT  ActiveIccLevelVccQ2[16];
} UFS_POWER_DESC;

//
// UFS 2.0 Spec Section 14.1.6.8 - InterConnect Descriptor
//
typedef struct {
  UINT8  Length;
  UINT8  DescType;
  UINT16 UniProVer;
  UINT16 MphyVer;
} UFS_INTER_CONNECT_DESC;

//
// UFS 2.0 Spec Section 14.1.6.9 - 14.1.6.12 - String Descriptor
//
typedef struct {
  UINT8  Length;
  UINT8  DescType;
  CHAR16 Unicode[126];
} UFS_STRING_DESC;

//
// UFS 2.0 Spec Section 14.2 - Flags
//
typedef enum {
  UfsFlagDevInit         = 0x01,
  UfsFlagPermWpEn        = 0x02,
  UfsFlagPowerOnWpEn     = 0x03,
  UfsFlagBgOpsEn         = 0x04,
  UfsFlagPurgeEn         = 0x06,
  UfsFlagPhyResRemoval   = 0x08,
  UfsFlagBusyRtc         = 0x09,
  UfsFlagPermDisFwUpdate = 0x0B
} UFS_FLAGS_IDN;

//
// UFS 2.0 Spec Section 14.2 - Attributes
//
typedef enum {
  UfsAttrBootLunEn         = 0x00,
  UfsAttrCurPowerMode      = 0x02,
  UfsAttrActiveIccLevel    = 0x03,
  UfsAttrOutOfOrderDataEn  = 0x04,
  UfsAttrBgOpStatus        = 0x05,
  UfsAttrPurgeStatus       = 0x06,
  UfsAttrMaxDataInSize     = 0x07,
  UfsAttrMaxDataOutSize    = 0x08,
  UfsAttrDynCapNeeded      = 0x09,
  UfsAttrRefClkFreq        = 0x0a,
  UfsAttrConfigDescLock    = 0x0b,
  UfsAttrMaxNumOfRtt       = 0x0c,
  UfsAttrExceptionEvtCtrl  = 0x0d,
  UfsAttrExceptionEvtSts   = 0x0e,
  UfsAttrSecondsPassed     = 0x0f,
  UfsAttrContextConf       = 0x10,
  UfsAttrCorrPrgBlkNum     = 0x11
} UFS_ATTR_IDN;

typedef enum {
  UfsNoData                = 0,
  UfsDataOut               = 1,
  UfsDataIn                = 2,
  UfsDdReserved
} UFS_DATA_DIRECTION;


#pragma pack()

#endif

